#include "openlineedit.h"

#include <QHBoxLayout>
#include <QPixmap>
#include <QStyle>
#include <QLayoutItem>
#include <QFileDialog>
#include <QToolTip>
#include <QColor>
#include <QDebug>


class OpenLineEdit::OpenLineEditPrivate{
public:
	OpenLineEditPrivate(QWidget *parent, bool checkPath);
	~OpenLineEditPrivate();

	QWidget *m_pParent;

	QLineEdit *m_pLineEdit;
	QPushButton *m_pPushButton;

	ButtonPosition m_buttonPosition;
	ButtonAlign m_buttonAlign;
	ButtonMode m_buttonMode;
	AccessMode m_accessMode;

	bool m_checkPath;
	QFileInfo *m_pFileInfo;

	QColor *m_pTextColor;
	//methods
	void updateSize();

	void updatePosition();

	void showToolTip(const QString &text, const QPoint &where);

	void changeTextColor(const QColor &color);
};
//end of d-class declaration
//definitions of d-class methods

OpenLineEdit::OpenLineEditPrivate::
		OpenLineEditPrivate(QWidget *parent, bool checkPath) :
			m_pParent(parent),
			m_buttonPosition(OpenLineEdit::Inside),
			m_buttonAlign(OpenLineEdit::Right),
			m_buttonMode(OpenLineEdit::OpenFile),
			m_accessMode(OpenLineEdit::ReadOnly),
			m_checkPath(checkPath),
			m_pFileInfo(NULL),
			m_pTextColor(NULL)
{
}

OpenLineEdit::OpenLineEditPrivate::~OpenLineEditPrivate(){
	delete m_pPushButton;
	delete m_pLineEdit;
	delete m_pFileInfo;
	delete m_pTextColor;
}

void OpenLineEdit::OpenLineEditPrivate::updateSize(){
	if( OpenLineEdit::Outside == m_buttonPosition )
		return;

	int frameWidth =
			m_pLineEdit->style()->pixelMetric(
					QStyle::PM_DefaultFrameWidth );

	if( OpenLineEdit::Right == m_buttonAlign ){
		m_pLineEdit->setStyleSheet(
				QString("QLineEdit { padding-right: %1px;"
						"padding-left: 0px; } ").
				arg(m_pPushButton->sizeHint().width() +
					frameWidth + 1));
	}else{
		m_pLineEdit->setStyleSheet(
				QString("QLineEdit { padding-left: %1px;"
						"padding-right: 0px;} ").
				arg(m_pPushButton->sizeHint().width() +
					frameWidth + 1));
	}

	QSize msz = m_pLineEdit->minimumSizeHint();

	m_pLineEdit->setMinimumSize(
			qMax(msz.width(),
				 m_pPushButton->sizeHint().height() +
				 frameWidth * 2 + 2),
			qMax(msz.height(),
				 m_pLineEdit->sizeHint().height() +
				 frameWidth * 2 + 2)
			);
}

void OpenLineEdit::OpenLineEditPrivate::updatePosition(){
	QSize sz = m_pPushButton->sizeHint();
	int frameWidth =
			m_pLineEdit->style()->pixelMetric(
					QStyle::PM_DefaultFrameWidth);

	if( OpenLineEdit::Right == m_buttonAlign ){
		m_pPushButton->move(
				m_pLineEdit->rect().right() - frameWidth - sz.width(),
				(m_pLineEdit->rect().bottom() - sz.height())/2);
	}else{
		m_pPushButton->move(
				m_pLineEdit->rect().left() + frameWidth,
				(m_pLineEdit->rect().bottom() - sz.height())/2);
	}
}

void OpenLineEdit::OpenLineEditPrivate::showToolTip(const QString &text,
													const QPoint &where)
{
	QToolTip::showText(where, text, m_pParent);
}

void OpenLineEdit::OpenLineEditPrivate::changeTextColor(const QColor &color){
	const_cast<QPalette&>( m_pLineEdit->palette() )
			.setColor( QPalette::Text, color );
}

//end of d-class part
//------------------------------------------------------------------------------

OpenLineEdit::OpenLineEdit(QWidget *parent, bool checkPath) :
	QWidget(parent),
	d(new OpenLineEditPrivate(this, checkPath))
{
	QHBoxLayout *layout = new QHBoxLayout();

	setLayout( layout );

	layout->setMargin( 0 );
	layout->setContentsMargins( 0, 0, 0, 0 );
	layout->setSpacing( 0 );

	d->m_pLineEdit = new QLineEdit();

	layout->addWidget( d->m_pLineEdit );

	d->m_pPushButton = new QPushButton();
	d->m_pPushButton->setCursor( Qt::ArrowCursor );
	d->m_pPushButton->setStyleSheet("QPushButton { border: none;"
									"padding: 0px; }");

	connect( d->m_pPushButton, SIGNAL(clicked()),
			 this, SLOT(getFileName()) );

	if( OpenLineEdit::Inside == d->m_buttonPosition ){
		d->m_pPushButton->setParent( d->m_pLineEdit );
	}else{
		layout->addWidget( d->m_pPushButton );
	}

	QPixmap pixmap( ":/res/document-open-folder.png" );
	d->m_pPushButton->setText( "" );
	d->m_pPushButton->setIcon( QIcon(pixmap) );
	d->m_pPushButton->setIconSize( pixmap.size() );


	d->updateSize();

	if( d->m_checkPath ){
		d->m_pFileInfo = new QFileInfo();

		d->m_pFileInfo->setCaching( false );
		d->m_pTextColor = new QColor(d->m_pLineEdit->palette().text().color());

		connect( d->m_pLineEdit, SIGNAL(textEdited(QString)),
				 this, SLOT(textEdited(QString)) );
	}
}

OpenLineEdit::~OpenLineEdit(){
	delete d;

	delete layout();
}

QSize OpenLineEdit::sizeHint() const{
	if( OpenLineEdit::Outside == d->m_buttonPosition ){
		return QSize( d->m_pLineEdit->width() + d->m_pPushButton->width(),
					  d->m_pLineEdit->height() + d->m_pPushButton->height() );
	}
	return d->m_pLineEdit->sizeHint();
}

QSize OpenLineEdit::minimumSizeHint() const{
	if( OpenLineEdit::Outside == d->m_buttonPosition ){
		return QSize( d->m_pLineEdit->minimumSizeHint().width() +
					  d->m_pPushButton->minimumSizeHint().width(),
					  d->m_pLineEdit->minimumSizeHint().height() +
					  d->m_pPushButton->minimumSizeHint().height()
					);
	}

	return d->m_pLineEdit->minimumSize();
}

void OpenLineEdit::resizeEvent(QResizeEvent *event){
	if( OpenLineEdit::Outside == d->m_buttonPosition ){
		QWidget::resizeEvent(event);
		return;
	}

	d->updatePosition();
}

void OpenLineEdit::setButtonPosition(const OpenLineEdit::ButtonPosition &pos){
	if( OpenLineEdit::Inside == d->m_buttonPosition &&
		OpenLineEdit::Outside == pos )
	{
		d->m_pPushButton->setParent( NULL );

		if( OpenLineEdit::Left == d->m_buttonAlign ){
			QLayoutItem *item = layout()->takeAt(0);
			layout()->addWidget( d->m_pPushButton );
			layout()->addItem( item );
		}else
			layout()->addWidget( d->m_pPushButton );
	}

	if( OpenLineEdit::Outside == d->m_buttonPosition &&
		OpenLineEdit::Inside == pos )
	{
		d->m_pPushButton->setParent( d->m_pLineEdit );

		for( int i = layout()->count() - 1; i >= 0; i-- ){
			delete layout()->takeAt( i );
		}

		layout()->addWidget( d->m_pLineEdit );

		d->updatePosition();
	}


	d->m_buttonPosition = pos;

	d->updateSize();
}

void OpenLineEdit::setButtonAlign(const OpenLineEdit::ButtonAlign &align){
	if( OpenLineEdit::Outside == d->m_buttonPosition &&
		align != d->m_buttonAlign )
	{
		QHBoxLayout *layoutNew = new QHBoxLayout();
		for( int i = layout()->count() - 1; i >= 0; i-- ){
			QLayoutItem *item = layout()->takeAt(i);
			layoutNew->addItem( item );
		}
		delete layout();
		setLayout( layoutNew );
	}

	d->m_buttonAlign = align;

	d->updateSize();
}

OpenLineEdit::ButtonPosition OpenLineEdit::buttonPosition() const{
	return d->m_buttonPosition;
}

OpenLineEdit::ButtonAlign OpenLineEdit::buttonAlign() const{
	return d->m_buttonAlign;
}


void OpenLineEdit::setText(const QString &text){
	d->m_pLineEdit->setText( text );
}

QString OpenLineEdit::text() const{
	return d->m_pLineEdit->text();
}

void OpenLineEdit::setButtonText(const QString &text){
	d->m_pPushButton->setText( text );
}

QString OpenLineEdit::buttonText() const{
	return d->m_pPushButton->text();
}

void OpenLineEdit::setButtonIcon(const QString &icon){
	QPixmap tmpIcon(icon);
	d->m_pPushButton->setIcon( QIcon(tmpIcon) );
	d->m_pPushButton->setIconSize( tmpIcon.size());

	d->updateSize();
}

void OpenLineEdit::setButtonIcon(const QIcon &icon){
	QPixmap pixmap = icon.pixmap( 16, 16 );

	d->m_pPushButton->setIcon( QIcon(pixmap) );
	d->m_pPushButton->setIconSize( pixmap.size() );

	d->updateSize();
}

QIcon OpenLineEdit::buttonIcon() const{
	return d->m_pPushButton->icon();
}

void OpenLineEdit::getFileName(){
	QString fileName;

	switch( d->m_buttonMode ){
	case OpenLineEdit::OpenFile:
		fileName = QFileDialog::getOpenFileName( this, tr("Otwórz plik") );
		break;
	case OpenLineEdit::SaveFile:
		fileName = QFileDialog::getSaveFileName( this, tr("Zapisz plik") );
		break;
	case OpenLineEdit::Directory:
		fileName = QFileDialog::getExistingDirectory( this,
													  tr("Wybierz folder") );
		break;
	}


	if( fileName.isEmpty() )
		return;

	d->m_pLineEdit->setText( fileName );
	textEdited( fileName );
	d->m_pLineEdit->setModified( true );
}

void OpenLineEdit::setButtonMode(const OpenLineEdit::ButtonMode &mode){
	//default values;
	if( OpenLineEdit::OpenFile == mode ){
		d->m_accessMode = OpenLineEdit::ReadOnly;
	}else if( OpenLineEdit::SaveFile == mode ){
		d->m_accessMode = OpenLineEdit::WriteOnly;
	}else{
		d->m_accessMode = OpenLineEdit::FullAccess;
	}

	d->m_buttonMode = mode;
}

OpenLineEdit::ButtonMode OpenLineEdit::buttonMode() const {
	return d->m_buttonMode;
}

void OpenLineEdit::setAccessMode(const OpenLineEdit::AccessMode &mode){
	d->m_accessMode = mode;
}

OpenLineEdit::AccessMode OpenLineEdit::accessMode() const {
	return d->m_accessMode;
}


bool OpenLineEdit::isReadOnly() const {
	return d->m_pLineEdit->isReadOnly();
}

void OpenLineEdit::setReadOnly(const bool &readOnly){
	d->m_pLineEdit->setReadOnly( readOnly );
}

bool OpenLineEdit::checkPath() const {
	return d->m_checkPath;
}

void OpenLineEdit::setCheckPath(const bool &flag){
	d->m_checkPath = flag;
}

bool OpenLineEdit::isModified() const {
	return d->m_pLineEdit->isModified();
}

void OpenLineEdit::setModified(bool state){
	d->m_pLineEdit->setModified( state );
}

bool OpenLineEdit::isEmpty() const {
	return d->m_pLineEdit->text().isEmpty();
}

void OpenLineEdit::textEdited(const QString &text){

	if( !d->m_checkPath )
		return;

	d->m_pLineEdit->setToolTip("");
	d->showToolTip("", mapToGlobal(QPoint(0,5)));

	if( text.isEmpty() ){
		d->changeTextColor( *d->m_pTextColor );
		return;
	}

	d->m_pFileInfo->setFile( text );

	if( d->m_pFileInfo->exists() ){
		if( OpenLineEdit::Directory != d->m_buttonMode &&
			!d->m_pFileInfo->isFile() )
		{
			d->m_pLineEdit->setToolTip(tr("To nie jest plik"));
			d->showToolTip(d->m_pLineEdit->toolTip(), mapToGlobal(QPoint(0,5)));
			d->changeTextColor( QColor(Qt::darkGreen) );

		}else if( OpenLineEdit::Directory == d->m_buttonMode
				  && !d->m_pFileInfo->isDir() )
		{
			d->m_pLineEdit->setToolTip(tr("To nie jest folder"));
			d->showToolTip(d->m_pLineEdit->toolTip(), mapToGlobal(QPoint(0,5)));
			d->changeTextColor( QColor(Qt::darkGreen) );
		}else if( (OpenLineEdit::ReadOnly & d->m_accessMode)
				  && !d->m_pFileInfo->isReadable() )
		{
			d->m_pLineEdit->setToolTip(tr("Nie masz praw do odczytu"));
			d->showToolTip(d->m_pLineEdit->toolTip(), mapToGlobal(QPoint(0,5)));
			d->changeTextColor( QColor(Qt::darkGreen) );
		}else if( (OpenLineEdit::WriteOnly & d->m_accessMode)
			&& !d->m_pFileInfo->isWritable() )
		{
			d->m_pLineEdit->setToolTip(tr("Nie masz praw do zapisu"));
			d->showToolTip(d->m_pLineEdit->toolTip(), mapToGlobal(QPoint(0,5)));
			d->changeTextColor( QColor(Qt::darkGreen) );
		}else{

			d->changeTextColor( *d->m_pTextColor );
		}

	}else{
		d->m_pLineEdit->setToolTip(tr("Podana ścieżka nie istnieje"));
		d->changeTextColor( QColor(Qt::red) );
	}


}
